#include "ModbusHelper.h"

#include <QDebug>
#include <QEventLoop>
#include <QTimer>
#include <QUrl>
#include <functional>

using namespace QtPromise;

// 静态成员初始化
QMap<QString, QSharedPointer<SharedModbusDevice>> ModbusHelper::s_sharedDevices;
QMutex ModbusHelper::s_deviceMapMutex;

ModbusHelper::ModbusHelper(QObject* parent)
    : QObject(parent), currentUnitId(1), isOwnedDevice(false)
{
}

ModbusHelper::~ModbusHelper() { disconnectFromDevice(); }

bool ModbusHelper::createModbus_tcp(const QString& ipAddr, int port, int unit_id)
{
    disconnectFromDevice();

    currentUnitId = unit_id;
    isOwnedDevice = true;  // TCP设备独占，不共享

    // TCP设备每个实例独占一个连接，不需要共享
    QString identifier = QString("tcp:%1:%2").arg(ipAddr).arg(port);

    auto deviceCreator = [this, ipAddr, port]() -> QModbusClient* {
        auto* tcpClient = new QModbusTcpClient();
        tcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
        tcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, ipAddr);
        tcpClient->setTimeout(2000);
        tcpClient->setNumberOfRetries(3);
        return tcpClient;
    };

    sharedDevice = getOrCreateSharedDevice(identifier, deviceCreator);
    if (!sharedDevice) {
        return false;
    }

    // 连接信号
    connect(sharedDevice->device.data(), &QModbusDevice::stateChanged, this,
            &ModbusHelper::onModbusStateChanged);
    connect(sharedDevice->device.data(),
            QOverload<QModbusDevice::Error>::of(&QModbusDevice::errorOccurred), this,
            &ModbusHelper::onModbusErrorOccurred);

    return connectToDevice();
}

bool ModbusHelper::createModbus_rtu(const QString& portName, int baudRate, int slaveAddress)
{
    disconnectFromDevice();

    currentUnitId = slaveAddress;
    isOwnedDevice = false;  // RTU设备共享串口

    // RTU设备共享同一串口连接，通过不同的slaveAddress区分设备
    QString identifier = QString("rtu:%1:%2").arg(portName).arg(baudRate);

    auto deviceCreator = [portName, baudRate]() -> QModbusClient* {
        auto* rtuMaster = new QModbusRtuSerialMaster();
        rtuMaster->setConnectionParameter(QModbusDevice::SerialPortNameParameter, portName);
        rtuMaster->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudRate);
        rtuMaster->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
                                          QSerialPort::Data8);
        rtuMaster->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
                                          QSerialPort::OneStop);
        rtuMaster->setConnectionParameter(QModbusDevice::SerialParityParameter,
                                          QSerialPort::NoParity);
        rtuMaster->setTimeout(500);
        rtuMaster->setNumberOfRetries(3);
        return rtuMaster;
    };

    sharedDevice = getOrCreateSharedDevice(identifier, deviceCreator);
    if (!sharedDevice) {
        return false;
    }

    // 连接信号
    connect(sharedDevice->device.data(), &QModbusDevice::stateChanged, this,
            &ModbusHelper::onModbusStateChanged);
    connect(sharedDevice->device.data(),
            QOverload<QModbusDevice::Error>::of(&QModbusDevice::errorOccurred), this,
            &ModbusHelper::onModbusErrorOccurred);

    return connectToDevice();
}

bool ModbusHelper::connectToDevice()
{
    QModbusClient* device = getModbusDevice();
    if (!device) {
        setError("Modbus device not initialized");
        return false;
    }

    // 如果已经连接，直接返回成功
    if (device->state() == QModbusDevice::ConnectedState) {
        return true;
    }

    // 先设置事件循环和信号连接，避免竞态条件
    QEventLoop loop;
    QTimer timeout;
    timeout.setSingleShot(true);
    timeout.start(5000);  // 5秒超时

    connect(&timeout, &QTimer::timeout, &loop, &QEventLoop::quit);

    // 使用QMetaObject::Connection来管理连接，避免悬空引用
    QMetaObject::Connection stateConnection =
        connect(device, &QModbusDevice::stateChanged, [&loop](QModbusDevice::State state) {
            if (state == QModbusDevice::ConnectedState ||
                state == QModbusDevice::UnconnectedState) {
                loop.quit();
            }
        });

    // 如果是正在连接状态，不要重复连接，直接等待
    if (device->state() == QModbusDevice::ConnectingState) {
        // 设备正在连接中，直接等待
    } else {
        // 只有在未连接状态才调用connectDevice
        if (!device->connectDevice()) {
            disconnect(stateConnection);
            setError(device->errorString());
            return false;
        }
    }

    // 再次检查状态，如果在connectDevice()调用后立即变为Connected，直接返回
    if (device->state() == QModbusDevice::ConnectedState) {
        disconnect(stateConnection);
        return true;
    }

    loop.exec();

    // 断开临时连接
    disconnect(stateConnection);

    if (device->state() != QModbusDevice::ConnectedState) {
        setError("Failed to connect to modbus device: " + device->errorString());
        return false;
    }

    return true;
}

void ModbusHelper::disconnectFromDevice()
{
    if (sharedDevice) {
        QMutexLocker locker(&s_deviceMapMutex);

        // 减少引用计数
        sharedDevice->refCount--;

        // 如果是最后一个引用，则断开设备连接并从映射中移除
        if (sharedDevice->refCount <= 0) {
            if (sharedDevice->device) {
                sharedDevice->device->disconnectDevice();
            }
            s_sharedDevices.remove(sharedDevice->identifier);
        }

        sharedDevice.reset();
    }
}

void ModbusHelper::setError(const QString& error)
{
    lastError = error;
    emit errorOccurred(error);
}

void ModbusHelper::onModbusStateChanged(QModbusDevice::State state)
{
    qDebug() << "Modbus state changed to:" << state;
}

void ModbusHelper::onModbusErrorOccurred(QModbusDevice::Error error)
{
    QModbusClient* device = getModbusDevice();
    if (device) {
        setError(device->errorString());
        qDebug() << "Modbus error occurred:" << error << device->errorString();
    }
}

QSharedPointer<SharedModbusDevice> ModbusHelper::getOrCreateSharedDevice(
    const QString& identifier, std::function<QModbusClient*()> deviceCreator)
{
    QMutexLocker locker(&s_deviceMapMutex);

    // 检查是否已存在共享设备
    auto it = s_sharedDevices.find(identifier);
    if (it != s_sharedDevices.end()) {
        // 增加引用计数
        it.value()->refCount++;
        return it.value();
    }

    // 创建新的共享设备
    QModbusClient* device = deviceCreator();
    if (!device) {
        setError("Failed to create modbus device");
        return nullptr;
    }

    auto sharedDev = QSharedPointer<SharedModbusDevice>::create(device, identifier);
    s_sharedDevices.insert(identifier, sharedDev);

    return sharedDev;
}

QModbusClient* ModbusHelper::getModbusDevice() const
{
    return sharedDevice ? sharedDevice->device.data() : nullptr;
}

QPromise<QVector<quint16>> ModbusHelper::asyncRead(int addr, int count)
{
    return QPromise<QVector<quint16>>([=](const QPromiseResolve<QVector<quint16>>& resolve,
                                          const QPromiseReject<QVector<quint16>>& reject) {
        if (!sharedDevice) {
            setError("Modbus device not initialized");
            reject(lastError);
            return;
        }

        QMutexLocker locker(sharedDevice->operationMutex);
        QModbusClient* device = sharedDevice->device.data();

        if (!device || device->state() != QModbusDevice::ConnectedState) {
            setError("Modbus device not connected");
            reject(lastError);
            return;
        }

        QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, addr, count);
        auto reply = device->sendReadRequest(readUnit, currentUnitId);

        if (!reply) {
            setError("Failed to send read request");
            reject(lastError);
            return;
        }

        connect(reply, &QModbusReply::finished, [=]() {
            if (reply->error() != QModbusDevice::NoError) {
                setError("Read error: " + reply->errorString());
                reject(lastError);
            } else {
                QModbusDataUnit result = reply->result();
                QVector<quint16> data;
                data.reserve(result.valueCount());

                for (int i = 0; i < result.valueCount(); i++) {
                    data.append(result.value(i));
                }

                emit commSuccess();
                resolve(data);
            }
            reply->deleteLater();
        });
    });
}

QPromise<QVector<float>> ModbusHelper::asyncReadFloat(int addr, int count, int order)
{
    return QPromise<QVector<float>>([=](const QPromiseResolve<QVector<float>>& resolve,
                                        const QPromiseReject<QVector<float>>& reject) {
        asyncRead(addr, count * 2)  // 每个float需要2个寄存器
            .then([=](const QVector<quint16>& registers) {
                QVector<float> floats = registersToFloats(registers, order);
                resolve(floats);
            })
            .fail([=](const QString& error) { reject(error); });
    });
}

QPromise<void> ModbusHelper::asyncWrite(int addr, const QVector<quint16>& values)
{
    return QPromise<void>(
        [=](const QPromiseResolve<void>& resolve, const QPromiseReject<void>& reject) {
            if (!sharedDevice) {
                setError("Modbus device not initialized");
                reject(lastError);
                return;
            }

            QMutexLocker locker(sharedDevice->operationMutex);
            QModbusClient* device = sharedDevice->device.data();

            if (!device || device->state() != QModbusDevice::ConnectedState) {
                setError("Modbus device not connected");
                reject(lastError);
                return;
            }

            QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, addr, values.size());
            for (int i = 0; i < values.size(); i++) {
                writeUnit.setValue(i, values[i]);
            }

            auto reply = device->sendWriteRequest(writeUnit, currentUnitId);

            if (!reply) {
                setError("Failed to send write request");
                reject(lastError);
                return;
            }

            connect(reply, &QModbusReply::finished, [=]() {
                if (reply->error() != QModbusDevice::NoError) {
                    setError("Write error: " + reply->errorString());
                    reject(lastError);
                } else {
                    emit commSuccess();
                    resolve();
                }
                reply->deleteLater();
            });
        });
}

QPromise<void> ModbusHelper::asyncWrite(int addr, const QVector<float>& values, int order)
{
    QVector<quint16> registers = floatsToRegisters(values, order);
    return asyncWrite(addr, registers);
}

QVector<quint16> ModbusHelper::floatsToRegisters(const QVector<float>& values, int order)
{
    QVector<quint16> registers;
    registers.reserve(values.size() * 2);

    for (float value : values) {
        union {
            float f;
            quint32 i;
        } converter;
        converter.f = value;

        quint16 high = (converter.i >> 16) & 0xFFFF;
        quint16 low = converter.i & 0xFFFF;

        // 根据字节序排列
        switch (order) {
            case MB_ABCD:  // MB_ABCD
                registers.append(high);
                registers.append(low);
                break;
            case MB_BADC:  // MB_BADC
                registers.append(((high << 8) & 0xFF00) | ((high >> 8) & 0x00FF));
                registers.append(((low << 8) & 0xFF00) | ((low >> 8) & 0x00FF));
                break;
            case MB_CDAB:  // MB_CDAB
                registers.append(low);
                registers.append(high);
                break;
            case MB_DCBA:  // MB_DCBA
                registers.append(((low << 8) & 0xFF00) | ((low >> 8) & 0x00FF));
                registers.append(((high << 8) & 0xFF00) | ((high >> 8) & 0x00FF));
                break;
            default:
                registers.append(high);
                registers.append(low);
                break;
        }
    }

    return registers;
}

QVector<float> ModbusHelper::registersToFloats(const QVector<quint16>& registers, int order)
{
    QVector<float> floats;
    floats.reserve(registers.size() / 2);

    for (int i = 0; i < registers.size() - 1; i += 2) {
        quint16 reg1 = registers[i];
        quint16 reg2 = registers[i + 1];

        quint32 combined;

        // 根据字节序重组
        switch (order) {
            case MB_ABCD:  // MB_ABCD
                combined = (static_cast<quint32>(reg1) << 16) | reg2;
                break;
            case MB_BADC:  // MB_BADC
                reg1 = ((reg1 << 8) & 0xFF00) | ((reg1 >> 8) & 0x00FF);
                reg2 = ((reg2 << 8) & 0xFF00) | ((reg2 >> 8) & 0x00FF);
                combined = (static_cast<quint32>(reg1) << 16) | reg2;
                break;
            case MB_CDAB:  // MB_CDAB
                combined = (static_cast<quint32>(reg2) << 16) | reg1;
                break;
            case MB_DCBA:  // MB_DCBA
                reg1 = ((reg1 << 8) & 0xFF00) | ((reg1 >> 8) & 0x00FF);
                reg2 = ((reg2 << 8) & 0xFF00) | ((reg2 >> 8) & 0x00FF);
                combined = (static_cast<quint32>(reg2) << 16) | reg1;
                break;
            default:
                combined = (static_cast<quint32>(reg1) << 16) | reg2;
                break;
        }

        union {
            float f;
            quint32 i;
        } converter;
        converter.i = combined;
        floats.append(converter.f);
    }

    return floats;
}